Sur un tableau de n éléments (numérotés de 0 à N-1), le tri par sélection
Le coeur de l'algorithme consiste à trouver l'indice de l'élément le plus petit dans la partie du tableau pas encore triée, par exemple à partir de l'élément d'indice p. Ecrivons cette fonction
def plus_petit_element(T,p):
N = len(T)
iMin = p
for i in range(p+1,N):
if T[i] < T[iMin]:
iMin = i
return iMin
T = [ 5, 8, 4, 3, 2, 1, 7, 6 ]
iMin = plus_petit_element(T,0)
print("Plus petit élément: T [",iMin,"] =",T[iMin])
Plus petit élément: T [ 5 ] = 1
Une fois le plus petit élément trouvé on veut le placer en tête de tableau (de la partie du tableau qui reste à trier)
Mais ... il faut conserver la valeur qui était en tête
Donc ... on échange les éléments en tête et minimum.
T[iMin],T[0] = T[0],T[iMin] # swap
print(T[:1],T[1:]) # T[:1] est la partie triée
[1] [8, 4, 3, 2, 5, 7, 6]
Le premier élément est donc en place mais le reste du tableau, d'indices 1 à N-1, reste à trier. Répétons l'opération pour l'indice 1
iMin = plus_petit_element(T,1)
T[iMin],T[1] = T[1],T[iMin]
print(T[:2],T[2:])
[1, 2] [4, 3, 8, 5, 7, 6]
Pour l'indice 2
iMin = plus_petit_element(T,2); T[iMin],T[2] = T[2],T[iMin];
print(T[:3],T[3:])
[1, 2, 3] [4, 8, 5, 7, 6]
Pour les indices 3 à 7
iMin = plus_petit_element(T,3); T[iMin],T[3] = T[3],T[iMin];
print(T[:4],T[4:])
[1, 2, 3, 4] [8, 5, 7, 6]
iMin = plus_petit_element(T,4); T[iMin],T[4] = T[4],T[iMin];
print(T[:5],T[5:])
[1, 2, 3, 4, 5] [8, 7, 6]
iMin = plus_petit_element(T,5); T[iMin],T[5] = T[5],T[iMin];
print(T[:6],T[6:])
[1, 2, 3, 4, 5, 6] [7, 8]
iMin = plus_petit_element(T,6); T[iMin],T[6] = T[6],T[iMin];
print(T[:7],T[7:])
[1, 2, 3, 4, 5, 6, 7] [8]
Il faut répéter recherche du minimum et échange pour toutes les positions de 0 à N-2.
Il n'est pas nécessaire de le faire pour l'indice N-1: un tableau de 1 élément est toujours trié.
T = [ 5, 8, 4, 3, 2, 1, 7, 6 ]
N = len(T)
for i in range(0,N-1):
iMin = plus_petit_element(T,i)
T[iMin],T[i] = T[i],T[iMin] # swap
print(T[:i+1],T[i+1:]) # T[:i+1] est la partie triée
[1] [8, 4, 3, 2, 5, 7, 6] [1, 2] [4, 3, 8, 5, 7, 6] [1, 2, 3] [4, 8, 5, 7, 6] [1, 2, 3, 4] [8, 5, 7, 6] [1, 2, 3, 4, 5] [8, 7, 6] [1, 2, 3, 4, 5, 6] [7, 8] [1, 2, 3, 4, 5, 6, 7] [8]
Le tri par sélection effectue deux boucles imbiquées.
def tri_par_selection(T,comparer = asd1.plus_petit):
N = len(T)
for i in range(0,N-1):
jMin = i
for j in range(i+1,N):
if comparer(T[j],T[jMin]):
jMin = j
asd1.echanger(T,i,jMin)
Pour évaluer la complexité de cet algorithme, trions un tableau au contenu généré aléatoirement
asd1.evalue_complexite(tri_par_selection,
asd1.tableau_aleatoire,
"tri par sélection, tableau aléatoire")
Nous voyons que le nombre de comparaisons a une complexité quadratique en $\Theta(n^2)$ pour trier $n$ éléments.
Pour être plus précis, il y a exactement $n(n-1)/2$ comparaisons, comme pour le tri à bulles.
Par contre, le nombre d'échanges évolue avec une complexité linéaire $\Theta(n)$
Plus précisément, il y a $n-1$ échanges.
A la lecture de l'algorithme, ces nombres de comparaisons et d'échanges sont évidemment indépendants du contenu du tableau à trier. Il n'est dès lors par nécessaire d'effectuer d'autres tests.
Le tri par sélection n'est pas stable.
L'échange T[jMin],T[i] = T[i],T[jMin]
déplace l'élément T[i]
à une position arbitraire du tableau sans tenir compte de sa valeur, éventuellement au delà d'un élément égal.
asd1.test_stabilite(tri_par_selection)
Le tri n'est pas stable
Finalement, visualisons graphiquement le tri de 20 entiers aléatoires entre 0 et 100
import numpy as np
T = np.random.randint(0,100,20)
asd1.afficheIteration(T,'Tableau original')
i = 0
iMin = plus_petit_element(T,i)
T[iMin],T[i] = T[i],T[iMin]
asd1.afficheIteration(T,'Iteration {0}'.format(i))
i += 1
iMin = plus_petit_element(T,i)
T[iMin],T[i] = T[i],T[iMin]
asd1.afficheIteration(T,'Iteration {0}'.format(i))
i += 1
iMin = plus_petit_element(T,i)
T[iMin],T[i] = T[i],T[iMin]
asd1.afficheIteration(T,'Iteration {0}'.format(i))
for k in range(10):
i += 1
iMin = plus_petit_element(T,i)
T[iMin],T[i] = T[i],T[iMin]
asd1.afficheIteration(T,'Iteration {0}'.format(i))
while i < len(T)-1:
i += 1
iMin = plus_petit_element(T,i)
T[iMin],T[i] = T[i],T[iMin]
asd1.afficheIteration(T,'Iteration {0}'.format(i))
© Olivier Cuisenaire, 2018 |